// 一、请说出下列最终的执行结果，并解释为什么

var a = []
for (var i = 0; i < 10; i++) {
   a[i] = function () {
      console.log(i)
   }
}
a[6]()

/**
 * 答：结果为10, 因为此处的for循环中给a每个下标位置保存的函数中的i
 * 都是指向全局声明的i变量，当for循环执行结束后i已经变成了10，所以
 * a每个位置的函数输出都是在打印全局中的i，也就是10
 */

// 二、请说出下列最终执行结果，并解释为什么。

var tmp = 123;
if (true) {
   console.log(tmp)
   let tmp
}

 /**
  * 答：会报错，因为在if体中使用了let 声明了一个会计作用域的变量tmp
  * 当浏览器查找tmp时会现在块级作用域中查找，查找不到才会到上一级一直到
  * 全局，但是块级作用域中是可以找得到的，只是let声明变量并不会发生变量
  * 提升，也就是说如果要使用该变量必须要在let 声明之后才可以，所以此处
  * 会报错
  */

// 三、结合ES6新语法，用最简单的方式找出数组中的最小值
var arr = [12, 34, 32, 89, 4]

let minNum
for (let i of arr) {
   minNum = arr.find(item => item < minNum) || i
   console.log('inner', minNum)
}
console.log(minNum) // 4

// 四、请详细说明var，let，const三种声明变量的方式之间的具体差别

/**
 * 答：1.var和let声明的是变量，const 声明的是常量，变量的内存指针可以
 * 发生改变，常量不行； 2.var声明的是基于函数/全局作用域的变量，let和const声明
 * 的是基于块级作用域的变量；3.var声明变量会产生变量提升，let和const不会
 */

// 五、情说出下列代码最终输出的结果，并解释为什么。

var a = 10;
var obj = {
   a: 20,
   fn () {
      setTimeout(() => {
         console.log(this.a)
      })
   }
}
obj.fn()

/**
 * 答：输出结果是20，因为首先fn函数是在obj下调用的，所以fn的this指向
 * 指向的是obj，而虽然fn内部是一个定时器的异步函数，如果此处不是用的箭
 * 头函数，而是一个匿名函数，那么此处的输出就应该是10了，因为异步函数内
 * 部的函数调用实际是在局环境下调用的，所以this指向的应该是window，但是
 * 他内部的函数使用的是箭头函数，箭头函数没有this机制，其内部的this指向
 * 的是上一层作用域的this也就是obj，因此this.a是20，
 */

// 六、简述Symbol类型的用途

/**
 * 答：首先Symbol表示的是一个独一无二的值，并且可以作为对象的属性名,
 * 一旦作为对象的属性名后，Object.keys()、for...in、JSON.stringify()
 * 都会忽略该属性，所以Symbol类型非常适合作为对象的私有属性使用
 */

// 七、说说什么是浅拷贝，什么是深拷贝？

/**
 * 答：浅拷贝只复制指向某个对象的指针，而不复制对象本身，新旧对象还是共享
 * 同一块内存。但深拷贝会另外创造一个一模一样的对象，新对象跟原对象不共享
 * 内存，修改新对象不会改到原对象。
 */

// 八、请简述TypeScript与JavaScript之间的关系

/**
 * 答：TypeScript是JavaScript的超集（在JavaScrip的基础上有一套拓展特性，
 * 最终会编译成为JavaScript）,在JavaScript的基础上拓展了类型系统，使其更
 * 加可靠（强类型）以及拓展了最新的ECMAScript的新特性。
 */

// 九、请谈谈你所认为的TypeScript优缺点。

/**
 * 答：
 * 优点：
 * 1.兼容性好，可以使用最新的ECMAScript的新特性，编译时最低可以转换成ES3版本
 * 2.环境支持很好，任何环境的JavaScript开发都支持（浏览器应用/node应用/RN/桌面应用）
 * 3.相较于Flow功能更强大，生态更健全、完善
 * 4.渐进式语言，可以以JavaScript为基础使用，学一个新特性用一个新特性
 * 5.强类型语言，可以在开发阶段避免很多类型问题，更可靠
 * 缺点：
 * 学习成本相对较高，语言本身相较于JavaScript多了很多概念
 */

// 十、描述引用计数的工作原理和优缺点

/**
 * 答：
 * 工作原理
 * 1.通过一个计数器，去统计对象空间的引用数，当对象的引用数为零的时候GC工作
 * 2.当这个对象空间的引用关系发生改变的时候，引用计数器就会主动修改当前对象的引用数值
 * 3.引用数字为0的时候立即执行回收
 * 优点
 * 1.发现垃圾时立即进行回收，只要发现引用次数为0了就会立即回收
 * 2.最大限度减少程序暂停（当程序内存快要占满，就会立刻去将引用次数为0的数据回收，释放内存空间）
 * 缺点
 * 1.无法回收循环引用对象
 * 2.资源消耗大，时间开销大（需要维护引用数值的变化，时刻监听着内容的引用）
 */

// 十一、描述标记整理算法的工作流程

/**
 * 答:
 * 第一个阶段：遍历所有对象找到所有活动对象（可达对象）进行标记
 * 第二个阶段：先执行整理操作，将活动的空间移动位置使其连续在一起，再遍历所有对象找到身上没有标
 * 记的对象进行清除，也会将身上有标记的对象的标记清除
 */

// 十二、描述V8中新生代存储区垃圾回收的流程

/**
 * 答：回收过程采用复制算法+标记整理算法
 * 首先新生代内存区也分为两个等大小空间From和To
 * 正在使用的空间From，空闲空间位To
 * 活动对象存储于From空间
 * 当From空间占满的时候执行标记整理算法，先将活动对象标记，然后将活动对象拷贝到To空间备份
 * 然后From空间执行完全释放，再将To空间和From空间进行交换，原本的From变成新的To（空闲状态空间），原本的To变成新的From（活动状态空间）
 * 在拷贝的过程中发现某个变量对象所存储的空间在老生代对象也会出现就会将新生代对象晋升到老生代对象中存储
 * 晋升就是将新生代对象移动到老生代
 * 可触发晋升的条件：
 * 如果有些对象经过一轮GC之后还存活，就进行晋升
 * 拷贝过程中To空间使用率超过25%就会将这一次的活动对象都晋升
 */

// 十三、描述增量标记算法在何时使用及工作原理

/**
 * 答：增量标记算法在V8引擎老生代存储区垃圾回收的时候执行，当垃圾回收执行的时候，会阻塞程序的执行的，
 * 所谓的增量标记就是把我们垃圾回收的操作分成多个小步，组合着完成垃圾回收，实现程序执行和垃圾回收交替执行，
 * 减少垃圾回收阻塞程序执行带给用户感受到的等待时间
 */